package org.juiceshop.gm;


import groovy.lang.Closure;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public abstract class MusicContainer extends MusicObject implements Iterable<MusicObject> {

	private List<MusicObject> _content = new LinkedList<MusicObject>();
	
	public MusicContainer () {}
	
	public MusicContainer (MusicObject ...args) {
		for (MusicObject arg : args) {
			add(arg);
		}
	}
	
	@Override
	public Iterator<MusicObject> iterator() {
		return _content.iterator();
	}

	public void add(MusicObject obj) {
		if (this.getClass().isInstance(obj)) {
			throw new IllegalArgumentException("Cannot add "+obj.getClass().getName()+" to "+this.getClass().getName());
		}
		MusicObject copy = obj.copy();
		copy.setParent(this);
		_content.add(copy);
	}
		
	public MusicObject get(int index) {
		if (index<0 || index>=_content.size()) {
			throw new IndexOutOfBoundsException("Cannot get element # "+index+" of "+size()+" elements.");
		}
		return _content.get(index);
	}
	
	public MusicObject getAt(int index) {
		return get(index);
	}
		
	
	@Override
	public int size() {
		return _content.size();
	}
	
	
	@Override
	public MusicContainer multiply (double n) {
		return transform("multiply",n);
	}
	
    @Override
	public MusicContainer div (double n) {
    	return transform("div",n);
    }
	
    @Override
    public MusicContainer transform(Closure closure) {
    	return transform("transform",closure);
    }
    
	@Override
	public MusicContainer transpose(int steps) {
		return transform("transpose",steps);
	}

    @Override
	public MusicContainer transform(String method, Object ... args) {
    	MusicContainer copy = emptyCopy();
    	for (MusicObject obj : this) {
    		copy.add(obj.transform(method,args));
    	}
    	return copy;
    }
	

	protected MusicContainer emptyCopy() {
		MusicContainer copy = (MusicContainer)super.copy();
		copy._content = new ArrayList<MusicObject>();
		return copy;
	}
		
	@Override
	public MusicContainer copy() {
		MusicContainer copy = emptyCopy();
		for (MusicObject obj : this) {
			copy.add(obj);
		}
		return copy;
	}
		
	protected String toString(char delimiter) {
		return "("+Util.join(this,delimiter)+")";
	}

    public List<MusicObject> asList() {
    	return Collections.unmodifiableList(_content);
    }
	
}
